home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / Sherlock 2.0 / DevLibSrc / Main_DevLib / LIBlog.c < prev    next >
Text File  |  1996-02-09  |  11KB  |  533 lines

  1. /*
  2.     devlib: log file handling routines.
  3.  
  4.     source:  LIBlog.c
  5.     started: December 14, 1990
  6.     version:
  7.         February 5, 1996.
  8.             Added support for Symantec C.
  9.         October 28, 1995.
  10.             Removed log_abort routine.
  11.             This clarifies where SysBeep is called.
  12.         September 25, 1995.
  13.             Added support for Code Warrior.
  14.         August 31, 1991.
  15.             Write to stderr instead of stdout, even for Tuple C.
  16.         July 16, 1994.
  17.             Added log_clanks.
  18.         December 13, 1993.
  19.             Initialize log_newlines to 1 so an initial cnl() does nothing.
  20. */
  21. #include <LIBlib.h>
  22. #include <LIBend.h>
  23. #include <LIBlog.h>
  24. #include <LIBmem.h>
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29.  
  30. /*
  31.     LOG_DOCUMENT_CREATOR sets the "Creator" field for log files.
  32.     Single quotes must be used.
  33.  
  34.     '????' specifies a generic document.
  35.     'KAHL' specifies a LightSpeed C document.
  36.     'MMCC' specifies a Code Warrior document.
  37.  
  38.     #define USE_STD_IO if you want to use ANSI Standard I/O.
  39.  
  40.     The *only* reason for having Mac-specific routines in this file
  41.     is so that they set the document's "creator" field.
  42. */
  43.  
  44. #if defined(THINK_C) || defined(SYMANTEC_C) || defined(__MWEKRS__)
  45.  
  46.     #undef  USE_STD_IO    /* Use Mac  routines: can   set 'creator' field. */
  47.     #define LOG_DOCUMENT_CREATOR 'KAHL'
  48.  
  49.     #include <Files.h>
  50.     #include <StandardFile.h>
  51.     #include <string.h>
  52.  
  53.     #include <pascal.h>
  54.     
  55.     #include <mac_gui.h>
  56.  
  57. #elif defined(__MWERKS__)
  58.  
  59.     #undef  USE_STD_IO    /* Use Mac  routines: can   set 'creator' field. */
  60.     #define LOG_DOCUMENT_CREATOR 'MMCC'
  61.     
  62.     #include <Files.h>
  63.     #include <StandardFile.h>
  64.     #include <string.h>
  65.     
  66.     #include <mac_gui.h>
  67.     
  68. #elif defined(applec)
  69.  
  70.     #undef  USE_STD_IO    /* Use Mac  routines: can   set 'creator' field. */
  71.     #define LOG_DOCUMENT_CREATOR '????'
  72.     
  73.     #define PtoCstr(a) p2cstr(a)
  74.     #define CtoPstr(a) c2pstr(a)
  75.     
  76.     #include <Errors.h>
  77.     #include <Files.h>
  78.     #include <Packages.h>
  79.     #include <Strings.h>
  80.     #include <String.h>
  81.  
  82. #else
  83.  
  84.     #define USE_STD_IO    /* Use ANSI routines: can't set 'creator' field. */
  85.     #define LOG_DOCUMENT_CREATOR '????'
  86.     
  87.     #include <stdio.h>
  88.     #include <string.h>
  89.  
  90. #endif
  91.  
  92. /*
  93.     Define local variables.
  94. */
  95. static int         log_count = 0;                 /* Buffer count. */
  96. static int        log_newlines = 1;            /* Consecutive newline count. */
  97. static char    *    log_fileName = NULL;        /* Trace file name. */
  98. static int        log_open_flag    = FALSE;    /* Logging enable flag. */
  99. static short    log_vRefNum;                /* volume reference number. */
  100. static FILE *    log_file = NULL;            /* File info. */
  101.  
  102. #define LOG_BUF_COUNT_MAX 150        /* Newlines will be inserted after this many chars. */
  103. static char    *log_buffer = NULL;        /* Output line buffer.    */
  104.  
  105. /*
  106.     Function prototypes of internal routines.
  107. */
  108. static void log_error    (char * message, char * fileName, int err_code);
  109. static void    log_write    (char * buffer, long count);
  110.  
  111. /*
  112.     Close the log file if it is open.
  113. */
  114. void
  115. log_close(void)
  116. {
  117.     if (log_open_flag) {
  118.  
  119.         ecnl(); es("closing log file: "); es(log_fileName); enl();
  120.  
  121.         /* Close the file. */
  122.         #ifdef USE_STD_IO
  123.             fclose(log_file);
  124.         #else
  125.             FSClose(log_vRefNum);
  126.             FlushVol(0L, log_vRefNum);
  127.         #endif
  128.  
  129.         /* Mark the file as closed. */
  130.         log_open_flag = FALSE;
  131.     }
  132. }
  133.  
  134. /*
  135.     Conditional blanks.
  136.     Output blanks to the indicated column.
  137. */
  138. void
  139. log_cblanks(short n)
  140. {
  141.     n = n-log_count;
  142.     n = min(n, LOG_BUF_COUNT_MAX);
  143.     while (n-- > 0) {
  144.         log_cout(' ');
  145.     }
  146. }
  147.  
  148. /*
  149.     Conditional new line.
  150.     Output a newline if there are characters already in the line.
  151. */
  152. void
  153. log_cnl(void)
  154. {
  155.  
  156.     if (log_newlines == 0) {
  157.         log_cout('\n');
  158.     }
  159. }
  160.  
  161. /*
  162.     Insure at least n consecutive newlines.
  163. */
  164. void
  165. log_cnls(short n)
  166. {
  167.     int i;
  168.  
  169.     for (i = n - log_newlines; i > 0; i--) {
  170.         log_cout('\n');
  171.     }
  172. }
  173.  
  174. /*
  175.     Output a character to the log window, the log file, or both.
  176.     All es output eventually goes through this routine.
  177.  
  178.     Keep track of the number of consecutive newlines for log_cnl and log_cnls.
  179. */
  180. void
  181. log_cout(char c)
  182. {
  183.     int temp_count = 0;
  184.  
  185.     /* Bug fix: 5/18/92 */
  186.     if (log_buffer == NULL) {
  187.         log_buffer = lib_calloc( (size_t) 1, LOG_BUF_COUNT_MAX);
  188.         if (log_buffer == NULL) {
  189.             end_abort();
  190.         }
  191.         log_count = 0;
  192.     }
  193.  
  194.     /* Use 4-space tabs. */
  195.     if (c == '\t') {
  196.  
  197.         register int pad = 4 - (log_count % 4);
  198.         register int i;
  199.  
  200.         for (i = 0; i < pad && log_count < LOG_BUF_COUNT_MAX-10; i++) {
  201.             log_buffer[log_count++] = ' ';
  202.         }
  203.         log_newlines = 0;
  204.         return;
  205.     }
  206.  
  207.     /* Ignore unprintable characters. */
  208.     if (c < 32 && c != '\n') {
  209.         log_newlines = 0;
  210.         return;
  211.     }
  212.  
  213.     /*
  214.         Buffer all characters until a newline arrives.
  215.         This buffering greatly speeds up file and window output.
  216.     */
  217.  
  218.     if (c != '\n') {
  219.  
  220.         /* Add the character. */
  221.         log_buffer[log_count++] = c;
  222.         
  223.         /*
  224.             6/3/94: Add a newline if the buffer is nearly full.
  225.             This allows a smaller buffer and makes the log easier to read.
  226.         */
  227.         if (log_count < LOG_BUF_COUNT_MAX-10) {
  228.             log_newlines = 0;
  229.             return;
  230.         }
  231.         else {
  232.             c = '\n';
  233.         }
  234.     }
  235.  
  236.     /* Finish off the buffer. */
  237.     log_newlines++;
  238.  
  239.     /* The Mac-specific translation from '\n' to '\r' is handled in slw_write. */
  240.     log_buffer[log_count++] = '\n';
  241.     log_buffer[log_count] = '\0';
  242.  
  243.     /* Kludge: save log_count so it can be restored later. */
  244.     temp_count = log_count;
  245.  
  246.     #ifdef SHERLOCK
  247.         sl_ovb();
  248.     #endif
  249.  
  250.     /* Write the line to the log window or to standard error. */
  251.     #if defined(THINK_C) || defined(SYMANTEC_C) || defined(__MWERKS__)
  252.  
  253.         /*
  254.             Reset log_count before calling slw_write so we 
  255.             won't print the line twice if slw_write calls end_quit.
  256.         */
  257.         
  258.         #if 0 /* try mixed windows. */
  259.         if (lib_stderr_flag) {
  260.             log_count = 0;
  261.             fwrite(&log_buffer[0],1,temp_count,stderr);
  262.         }
  263.         else {
  264.             log_count = 0;
  265.             slw_write(&log_buffer[0], temp_count);
  266.         }
  267.         #endif
  268.         
  269.         log_count = 0;
  270.         slw_write(&log_buffer[0], temp_count);
  271.  
  272.     #else
  273.  
  274.     {
  275.         register char * s;
  276.         register char c;
  277.         for (s = &log_buffer[0]; c = *s; s++) {
  278.  
  279.             /* 5/26/93: Use stderr in MPW so that I/O is not buffered. */
  280.             #ifdef applec
  281.                 /*
  282.                     Interchange '\r' and '\n'.
  283.                     The standard file routines do this automatically.
  284.                     Note that MPW C interchanges these at *compile*
  285.                     time so this does not have to be done at run time.
  286.                 */
  287.                 if (c == '\r') {
  288.                     c = '\n';
  289.                 }
  290.                 else if (c == '\n') {
  291.                     c = '\r';
  292.                 }
  293.                 fputc(c, stderr);
  294.             #else
  295.                 /* A standard OS should get this right. */
  296.                 #if 0
  297.                     putchar(*s);
  298.                 #endif
  299.                 fputc(c, stderr);
  300.             #endif
  301.         }
  302.     }
  303.  
  304.     #endif
  305.  
  306.     /*
  307.         Write the completed line to the log file if open.
  308.         Write this *after* writing to the window so
  309.         log_write is free to interchange '\n' and '\r'.
  310.     */
  311.     if (log_open_flag) {
  312.  
  313.         /* Restore the proper count now that we know end_quit has not been called. */
  314.         log_count = temp_count;
  315.         log_write(&log_buffer[0], log_count);
  316.     }
  317.  
  318.     /* Clear out the buffer. */
  319.     log_count = 0;
  320.  
  321.     #ifdef SHERLOCK
  322.         sl_ovx();
  323.     #endif
  324. }
  325.  
  326. /*
  327.     Give an error message.
  328. */
  329. static void
  330. log_error(char * message, char * fileName, int err_code)
  331. {
  332.     es(message); eblank();
  333.     es(fileName); eblank();
  334.     elp(); log_errout(err_code); erpnl();
  335. }
  336.  
  337. /*
  338.     Return TRUE if the log file is open.
  339. */
  340. int
  341. log_isopen(void)
  342. {
  343.     return log_open_flag;
  344. }
  345.  
  346. /*
  347.     Close the log file if it is open, then
  348.     open the named file for writing, erasing it if it exists.
  349.  
  350.     The *only* reason for using Mac-specific routines here is that
  351.     Create sets the document's "creator" field.
  352. */
  353. void
  354. log_open(char * fileName)
  355. {
  356.     log_open_vRefNum(0, fileName);
  357. }
  358.  
  359. void
  360. log_open_vRefNum(short vRefNum, char * fileName)
  361. {
  362.  
  363. #ifndef USE_STD_IO
  364.  
  365.     OSErr    err;        /* File error code.                */
  366.     Str255    pFileName;    /* Pascal File Name.            */
  367.  
  368. #endif
  369.  
  370.     if (fileName == (char *) 0 || fileName[0] == '\0') {
  371.  
  372.         /* This should never happen. */
  373.         es("log_open: null file name\n");
  374.         return;
  375.     }
  376.  
  377.     /*
  378.         Close a file if it is open.
  379.         This can happen if >file is chosen from the options menu.
  380.     */
  381.     if (log_open_flag) {
  382.         ecnl(); es("Closing log file: "); es(log_fileName); enl();
  383.         log_close();
  384.     }
  385.  
  386. #ifdef USE_STD_IO
  387.  
  388.     log_file = fopen(fileName, "w");
  389.     if (log_file == NULL) {
  390.         es("Can not open log file: "); es(fileName); enl();
  391.         return;
  392.     }
  393.  
  394. #else
  395.  
  396.     strcpy( (char *) &pFileName, fileName);
  397.     CtoPstr( (char *) &pFileName);
  398.  
  399.     /* See if the file exists. */
  400.     err = FSOpen((pstring) &pFileName, vRefNum, &log_vRefNum);
  401.     if (err != noErr && err != fnfErr) {
  402.         log_cnl();
  403.         log_error("Can not open", fileName, err);
  404.         return;
  405.     }
  406.  
  407.     if (err == noErr) {
  408.  
  409.         /* File is open.  Just erase it. */
  410.         SetEOF(log_vRefNum, 0L);
  411.     }
  412.     else {
  413.  
  414.         /* Create the file. */
  415.         err = Create((pstring) pFileName, vRefNum,
  416.             (OSType) LOG_DOCUMENT_CREATOR, (OSType) 'TEXT');
  417.  
  418.         if (err != noErr) {
  419.             log_cnl();
  420.             log_error("Can not create log file: ", fileName, err);
  421.             return;
  422.         }
  423.  
  424.         /* Open the file and set log_vRefNum. */
  425.         err = FSOpen(pFileName, vRefNum, &log_vRefNum);
  426.         if (err != noErr) {
  427.             log_cnl();
  428.             log_error("Can not open log file: ", fileName, err);
  429.             return;
  430.         }
  431.     }
  432.     
  433. #endif
  434.  
  435.     /*
  436.         We have opened the file successfully.
  437.  
  438.         Set the global file name, and file flag.
  439.     */
  440.     if (log_fileName == NULL) {
  441.         log_fileName = lib_calloc( (size_t) 1, MAX_LOG_FILE_NAME);
  442.     }
  443.  
  444.     /* 5/13/93: Make sure we don't over-write the buffer. */
  445.     strncpy(log_fileName, fileName, MAX_LOG_FILE_NAME-2);
  446.     log_fileName[MAX_LOG_FILE_NAME-2]= '\0';
  447.  
  448.     log_open_flag = TRUE;
  449.  
  450.     /* After this point, traces go to the log file. */
  451.     ecnl(); es("Opening log file: "); es(fileName); enl();
  452.     return;
  453. }
  454.  
  455. /*
  456.     Output a string to the standard output stream.
  457.  
  458.     Keep track of consecutive newlines.
  459. */
  460. void
  461. log_sout(char * s)
  462. {
  463.     while (*s) {
  464.         log_cout(*s++);
  465.     }
  466. }
  467.  
  468. /*
  469.     Write the buffer and to the file.
  470.     The caller is responsible for saving and restoring the grafPtr.
  471. */
  472. static void
  473. log_write(char * buffer, long length)
  474. {
  475.  
  476. #ifdef USE_STD_IO
  477.  
  478.     long count = 0;
  479.  
  480.     /* 7/28/93: Handle this translation here for the perverted MPW library. */
  481.     #ifdef applec
  482.         if (length && buffer[length-1] == '\n') {
  483.             buffer[length-1] = '\r';
  484.         }
  485.     #endif
  486.  
  487.     count = fwrite(buffer, 1, length, log_file);
  488.     if (count < 0) {
  489.         es("Error writing to "); es(log_fileName); enl();
  490.     }
  491.  
  492. #else
  493.  
  494.     OSErr    err;        /* File error code.        */
  495.     long    count=length;
  496.  
  497.     /* 5/13/93: Handle this translation here. */
  498.     if (count && buffer[count-1] == '\n') {
  499.         buffer[count-1] = '\r';
  500.     }
  501.  
  502.     err = FSWrite(log_vRefNum, &count, (Ptr) buffer);
  503.     if (err != noErr) {
  504.  
  505.         /*
  506.             Close the file before creating more output!
  507.             Don't call log_close:  it produces output.
  508.         */
  509.         FSClose(log_vRefNum);
  510.         log_open_flag = FALSE;
  511.  
  512.         log_cnl();
  513.         log_error("Error writing to", log_fileName, err);
  514.     }
  515.     
  516. #endif
  517.  
  518.     /* Check for truncated lines. */
  519.     if (count != length) {
  520.         log_cnl(); es("Write to "); es(log_fileName); es(" truncated\n");
  521.     }
  522. }
  523.  
  524. /*
  525.     Output a descriptive message corresponding to a file error code.
  526. */
  527. void
  528. log_errout(int OSErrCode)
  529. {
  530.     char buffer [CVT_BUF_SIZE];
  531.     es(cvt_file_error(buffer, CVT_BUF_SIZE, OSErrCode));
  532. }
  533.